//GNU C библиотека.
#include <sys/resource.h>


//Библиотека Qt.
#include <QtGui>


//Внутренняя библиотека.
#include "devmanagedialog.h"
#include "devmanager.h"
#include "devparamswidget.h"
#include "motionparamswidget.h"
#include "treedeviceitem.h"
#include "vidwidget.h"


//Глобальные константы.
#define DEVSWDG_DEVICE_COL 0
#define DEVSWDG_WINDOW_COL 1
#define DEVSWDG_MOTION_COL 2
#define DEVSWDG_NETWRK_COL 3


//===========================================================================//
//=Заголовок: DevManageDialog::DevManageDialog() - public
//=Параметры:
//=Описание: Конструктор.
//===========================================================================//
DevManageDialog::DevManageDialog(DevManager *devmanager, QWidget *parent) : QDialog(parent)
{
devManager = devmanager;
devManager->clearDevicesSelection();
connect(devManager, SIGNAL(reloadDevices()), this, SLOT(slotReloadDevices()));
connect(this, SIGNAL(devicesConnect(const QList<VidDevice *> &)), devManager, SIGNAL(devicesConnect(const QList<VidDevice *> &)));
connect(this, SIGNAL(devicesDisconnect(const QList<int> &)), devManager, SIGNAL(devicesDisconnect(const QList<int> &)));

//Установить заголовок окна.
setWindowTitle(trUtf8("Настройка параметров"));

//Создать виджеты управления устройствами.
QToolBar *toolbar = new QToolBar(this);

QAction *finddevsact = toolbar->addAction(QIcon(":/images/finddevs.png"), QString(), this, SLOT(slotFindDevices()));
finddevsact->setToolTip(tr("Поиск видеоустройств"));

QAction *adddevact = toolbar->addAction(QIcon(":/images/adddev.png"), QString(), this, SLOT(slotAddDevice()));
adddevact->setToolTip(tr("Добавить видеоустройство"));

QAction *addplayeract = toolbar->addAction(QIcon(":/images/addplayer.png"), QString(), this, SLOT(slotAddFilePlayer()));
addplayeract->setToolTip(tr("Добавить видеоплэйер"));

delDevAct = toolbar->addAction(QIcon(":/images/deldev.png"), QString(), this, SLOT(slotDeleteDevice()));
delDevAct->setToolTip(tr("Удалить видеоустройство"));
delDevAct->setEnabled(false);

//Создать визуальный список устройств.
devsWdg = new QTreeWidget(this);
devsWdg->setMinimumWidth(400);
devsWdg->setColumnCount(4);
devsWdg->setIconSize(QSize(24, 24));
devsWdg->addTopLevelItems(devManager->getDevicesGroupList(DEVSWDG_DEVICE_COL, DEVSWDG_WINDOW_COL, DEVSWDG_MOTION_COL, DEVSWDG_NETWRK_COL));
connect(devsWdg, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotDeviceClicked(QTreeWidgetItem *)));
connect(devsWdg, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(slotDeviceChanged(QTreeWidgetItem *, int)));

//Настроить заголовок визуального списка устройств.
QTreeWidgetItem *header_item = devsWdg->headerItem();
header_item->setText(DEVSWDG_DEVICE_COL, tr("Видеоустройства"));
header_item->setText(DEVSWDG_WINDOW_COL, "");
header_item->setIcon(DEVSWDG_WINDOW_COL, QIcon(":/images/monitor.png"));
header_item->setText(DEVSWDG_MOTION_COL, "");
header_item->setIcon(DEVSWDG_MOTION_COL, QIcon(":/images/motion.png"));
header_item->setText(DEVSWDG_NETWRK_COL, "");
header_item->setIcon(DEVSWDG_NETWRK_COL, QIcon(":/images/network.png"));

//Создать виджеты отображения информации о загрузке CPU.
QLabel *cpulabel = new QLabel(tr("Процессор:"), this);
cpuPBar = new QProgressBar(this);
cpuUsage = 0;

//Создать менеджер размещения.
QHBoxLayout *loadlayout = new QHBoxLayout();
loadlayout->setMargin(4); loadlayout->setSpacing(4);
loadlayout->addWidget(cpulabel);
loadlayout->addWidget(cpuPBar);

//Создать таймер для слежения за загрузкой системы.
QTimer *loadtimer = new QTimer(this);
loadtimer->setInterval(1000);
connect(loadtimer, SIGNAL(timeout()), this, SLOT(slotLoadTimerTimeout()));
loadtimer->start();

//Создать виджет смены типа видеоокон.
QComboBox *wintypecbox = new QComboBox(this);
wintypecbox->addItems(VidWidget::getTypesList());

//Получить тип видеоокна из файла настроек приложения.
QSettings settings;
QVariant vidwintype = settings.value("VIDWINTYPE", "XVIDEO");
wintypecbox->setCurrentIndex(wintypecbox->findText(vidwintype.toString()));
connect(wintypecbox, SIGNAL(activated(const QString &)), this, SIGNAL(vidWinTypeChange(const QString &)));

//Создать виджет смены параметров видеоустройств.
devParamsWdg = new DevParamsWidget(devManager, this);
devParamsWdg->clearWidgets();
connect(devParamsWdg, SIGNAL(information(const QString &)), this, SIGNAL(information(const QString &)));
connect(devParamsWdg, SIGNAL(warning(const QString &)), this, SIGNAL(warning(const QString &)));
connect(devParamsWdg, SIGNAL(critical(const QString &)), this, SIGNAL(critical(const QString &)));

//Создать виджет смены параметров ДД.
motionParamsWdg = new MotionParamsWidget(devManager, this);

//Создать виджет вкладок.
paramsTBWdg = new QTabWidget(this);
int tab_index = paramsTBWdg->addTab(devParamsWdg, QIcon(":/images/camera.png"), tr("Устройство"));
tab_index = paramsTBWdg->addTab(motionParamsWdg, QIcon(":/images/motion.png"), tr("Движение"));
paramsTBWdg->setTabEnabled(tab_index, false);

//Создать разделительную линию.
QLabel *bevellabel = new QLabel(this);
bevellabel->setFrameStyle(QFrame::HLine | QFrame::Sunken);

//Создать кнопку.
QPushButton *closebut = new QPushButton(tr("Закрыть"), this);
connect(closebut, SIGNAL(clicked()), this, SLOT(close()));

//Создать менеджер размещения.
QHBoxLayout *butlayout = new QHBoxLayout();
butlayout->setMargin(2); butlayout->setSpacing(2);
butlayout->addStretch(1);
butlayout->addWidget(closebut);

//Создать главный менеджер размещения.
QGridLayout *mainlayout = new QGridLayout(this);
mainlayout->setMargin(5); mainlayout->setSpacing(5);
mainlayout->addWidget(toolbar, 0, 0);
mainlayout->addWidget(devsWdg, 1, 0);
mainlayout->addLayout(loadlayout, 2, 0);
mainlayout->addWidget(wintypecbox, 0, 1);
mainlayout->addWidget(paramsTBWdg, 1, 1);
mainlayout->addWidget(bevellabel, 3, 0, 1, 2);
mainlayout->addLayout(butlayout, 4, 0, 1, 2);

//Отформатировать визуальный список устройств.
devsWidgetAdjust();
}


//===========================================================================//
//=Заголовок: DevManageDialog::~DevManageDialog() - public
//=Параметры:
//=Описание: Деструктор.
//===========================================================================//
DevManageDialog::~DevManageDialog() {devManager->clearDevicesSelection();}


//===========================================================================//
//=Заголовок: void DevManageDialog::setEnabledWidgets() - private
//=Параметры:
//=Описание: Функция управления доступностью виджетов.
//===========================================================================//
void DevManageDialog::setEnabledWidgets(bool enabled)
{delDevAct->setEnabled(enabled);}


//===========================================================================//
//=Заголовок: void DevManageDialog::devsWidgetAdjust() - private
//=Параметры:
//=Описание: Функция форматирования визуального списка устройств.
//===========================================================================//
void DevManageDialog::devsWidgetAdjust()
{
for(int i = 0; i < devsWdg->columnCount(); ++i)
	{devsWdg->resizeColumnToContents(i);}

for(int i = 0; i < devsWdg->topLevelItemCount(); ++i)
	{
	QTreeWidgetItem *item = devsWdg->topLevelItem(i);
	if(!item) continue;
	item->setExpanded(true);

	for(int ii = 0; ii < item->childCount(); ++ii)
		{item->child(ii)->setExpanded(true);}
}
}


//===========================================================================//
//=Заголовок: void DevManageDialog::setVideoWindowConnect() - private
//=Параметры:
//=Описание: Функция подключения или отключения видеоокон.
//===========================================================================//
void DevManageDialog::setVideoWindowConnect(TreeDeviceItem *item)
{
//Получить список устройств.
QList<VidDevice *> viddevlist = item->getDevicesList();
if(viddevlist.isEmpty()) return;

switch(item->checkState(DEVSWDG_WINDOW_COL))
	{
	case Qt::Unchecked: {
		//Выбрать индексы указанных устройств.
		QList<int> devindexlist;
		foreach(VidDevice *viddev, viddevlist)
			{
			if(!viddev) continue;
			devindexlist.append(viddev->getIndex());
		}

		//Отправить сигнал о необходимости отключения видеоокон.
		emit devicesDisconnect(devindexlist);
	} break;
	case Qt::Checked: {
		//Отправить сигнал о необходимости подключения видеоокон.
		emit devicesConnect(viddevlist);

		//Проверить, действительно ли созданы видеоокна
		//(если достигнуто их возможно максимальное кол-во).
		foreach(VidDevice *viddev, viddevlist)
			{
			if(!viddev) continue;
			QVariant devwinconnected;
			viddev->getParam(DevParam::GET_VIDEOWINDOW_CONNECTED, &devwinconnected);
			if(!devwinconnected.toBool()) item->setCheckState(DEVSWDG_WINDOW_COL, Qt::Unchecked);
		}
	} break;
	case Qt::PartiallyChecked: break;
}
}


//===========================================================================//
//=Заголовок: void DevManageDialog::setMotionConnect() - private
//=Параметры:
//=Описание: Функция подключения или отключения детектора движения.
//===========================================================================//
void DevManageDialog::setMotionConnect(TreeDeviceItem *item)
{devManager->setParam(DevParam::SET_MOTION_CONNECTED, (bool)item->checkState(DEVSWDG_MOTION_COL));}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotFindDevices() - private slots
//=Параметры:
//=Описание: Слот поиска устройств.
//===========================================================================//
void DevManageDialog::slotFindDevices()
{
//Выполнить поиск устройств.
devManager->loadDevicesFromSystem();

//Обновить визуальный список устройств.
slotReloadDevices();
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotAddDevice() - private slots
//=Параметры:
//=Описание: Слот добавления устройства.
//===========================================================================//
void DevManageDialog::slotAddDevice()
{
//Очистить список выбора устройств и виджеты параметров.
devManager->clearDevicesSelection();
devParamsWdg->clearWidgets();

//Показать диалог выбора файла устройства.
QString caption = tr("Выбор файла видеоустройства");
QString devfname = QFileDialog::getOpenFileName(this, caption,  "/dev", "video*", 0, QFileDialog::ReadOnly);
if(devfname.isEmpty()) return;

//Добавить новое устройство.
devManager->addDevice(devfname);

//Очистить и заполнить визуальный список устройств.
devsWdg->clear();
devsWdg->addTopLevelItems(devManager->getDevicesGroupList(DEVSWDG_DEVICE_COL, DEVSWDG_WINDOW_COL, DEVSWDG_MOTION_COL, DEVSWDG_NETWRK_COL));

//Отформатировать визуальный список устройств.
devsWidgetAdjust();

//Закрыть доступ к виджетам.
setEnabledWidgets(false);
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotAddFilePlayer() - private slots
//=Параметры:
//=Описание: Слот добавления файлового плэйера.
//===========================================================================//
void DevManageDialog::slotAddFilePlayer()
{
//Очистить список выбора устройств и виджеты параметров.
devManager->clearDevicesSelection();
devParamsWdg->clearWidgets();

//Показать диалог выбора пути, содержащего видеофайлы.
QString caption = tr("Выбор пути к видеофайлам");
QString	path = QFileDialog::getExistingDirectory(this, caption, qApp->applicationDirPath());

//Добавить файловый плэйер.
devManager->addFilePlayer(path);

//Очистить и заполнить визуальный список устройств.
devsWdg->clear();
devsWdg->addTopLevelItems(devManager->getDevicesGroupList(DEVSWDG_DEVICE_COL, DEVSWDG_WINDOW_COL, DEVSWDG_MOTION_COL, DEVSWDG_NETWRK_COL));

//Отформатировать визуальный список устройств.
devsWidgetAdjust();

//Закрыть доступ к виджетам.
setEnabledWidgets(false);
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotDeleteDevice() - private slots
//=Параметры:
//=Описание: Слот удаления устройства.
//===========================================================================//
void DevManageDialog::slotDeleteDevice()
{
TreeDeviceItem *item = (TreeDeviceItem *)devsWdg->currentItem();
if(!item) return;

//Получить список устройств.
QList<VidDevice *> viddevlist = item->getDevicesList();
if(viddevlist.isEmpty()) return;

devManager->clearDevicesSelection();
devParamsWdg->clearWidgets();

//Удалить указанные устройства.
devManager->deleteDevices(viddevlist);

//Очистить и заполнить визуальный список устройств.
devsWdg->clear();
devsWdg->addTopLevelItems(devManager->getDevicesGroupList(DEVSWDG_DEVICE_COL, DEVSWDG_WINDOW_COL, DEVSWDG_MOTION_COL, DEVSWDG_NETWRK_COL));

//Отформатировать визуальный список устройств.
devsWidgetAdjust();

//Закрыть доступ к виджетам.
setEnabledWidgets(false);
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotReloadDevices() - private slots
//=Параметры:
//=Описание: Слот обновления визуального списка устройств.
//===========================================================================//
void DevManageDialog::slotReloadDevices()
{
//Очистить список выбора устройств и виджеты параметров.
devManager->clearDevicesSelection();
devParamsWdg->clearWidgets();

//Очистить и заполнить визуальный список устройств.
devsWdg->clear();
devsWdg->addTopLevelItems(devManager->getDevicesGroupList(DEVSWDG_DEVICE_COL, DEVSWDG_WINDOW_COL, DEVSWDG_MOTION_COL, DEVSWDG_NETWRK_COL));

//Отформатировать визуальный список устройств.
devsWidgetAdjust();

//Закрыть доступ к виджетам.
setEnabledWidgets(false);
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotDeviceClicked() - private slots
//=Параметры:
//=Описание: Слот активации устройства в списке.
//===========================================================================//
void DevManageDialog::slotDeviceClicked(QTreeWidgetItem *wdgitem)
{
TreeDeviceItem *item = (TreeDeviceItem *)wdgitem;
if(!item) return;

//Получить список устройств.
QList<VidDevice *> viddevlist = item->getDevicesList();
if(viddevlist.isEmpty())
	{
	devManager->clearDevicesSelection();
	devParamsWdg->clearWidgets();
	return;
}

//Выбрать указанные устройства.
if(viddevlist.size() == 1) devManager->selectDevice(viddevlist.first());
else devManager->selectDevices(viddevlist);

//Открыть доступ к виджетам.
setEnabledWidgets(true);
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotDeviceChanged() - private slots
//=Параметры:
//=Описание: Слот изменения устройства в списке.
//===========================================================================//
void DevManageDialog::slotDeviceChanged(QTreeWidgetItem *wdgitem, int column)
{
TreeDeviceItem *item = (TreeDeviceItem *)wdgitem;
if(!item) return;
switch(column)
	{
	case DEVSWDG_WINDOW_COL: setVideoWindowConnect(item); break;
	case DEVSWDG_MOTION_COL: setMotionConnect(item); break;
}
}


//===========================================================================//
//=Заголовок: void DevManageDialog::slotLoadTimerTimeout() - private slots
//=Параметры:
//=Описание: Слот сработки таймера, отслеживающего загрузку системы.
//===========================================================================//
void DevManageDialog::slotLoadTimerTimeout()
{
rusage usage;
if(getrusage(RUSAGE_SELF, &usage) != 0) return;
double usr = usage.ru_utime.tv_sec + (usage.ru_utime.tv_usec * 1e-6);
double sys = usage.ru_stime.tv_sec + (usage.ru_stime.tv_usec * 1e-6);
double rusagecur = usr + sys;
cpuPBar->setValue((rusagecur - cpuUsage) / 1.0 * 100.0);
cpuUsage = rusagecur;
}
